#ifndef __threadPool_H__
#define __threadPool_H__

#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <functional>

//线程安全队列
template<typename T>
class CMyQueue
{
public:
    void push(const T& item)
    {
        {
            std::scoped_lock lock(m_mutex);
            m_queue.push(item);
        }
        m_cond.notify_one();
    }

    void push(T&& item)
    {
        {
            std::scoped_lock lock(m_mutex);
            m_queue.push(std::move(item));
        }
        m_cond.notify_one();
    }

    bool pop(T &item)
    {
        std::unique_lock lock(m_mutex);
        m_cond.wait(lock, [&](){
            return !m_queue.empty() || m_stop;
        });

        if(m_queue.empty())
        {
            return false;
        }

        item = std::move(m_queue.front());
        m_queue.pop();
        return true;
    }

    std::size_t size() const
    {
        std::scoped_lock lock(m_mutex);
        return m_queue.size();
    }

    bool empty() const
    {
        std::scoped_lock lock(m_mutex);
        return m_queue.empty();
    }

    void stop()
    {
        {
            std::scoped_lock lock(m_mutex);
            m_stop = true;
        }
        m_cond.notify_all();
    }
private:
    std::condition_variable m_cond;
    std::queue<T> m_queue;
    mutable std::mutex m_mutex;
    bool m_stop = false;
};



class CThreadPoll
{
public:
    explicit CThreadPoll(size_t threads = std::thread::hardware_concurrency())
    {
        for(size_t i = 0; i < threads; ++i)
        {
            m_threadWorker.emplace_back([this](){
                std::function<void()> task;
                while(1)
                {
                    if(!m_queue.pop(task))
                    {
                        return;
                    }

                    if(task)
                    {
                        task();
                    }
                }
            });
        }
    }

    void enqueue(std::function<void()> item)
    {
        m_queue.push(std::move(item));
    }

    ~CThreadPoll()
    {
        m_queue.stop();
        for(auto& t: m_threadWorker)
        {
            t.join();
        }
    }
private:
    CMyQueue<std::function<void()>> m_queue;
    std::vector<std::thread> m_threadWorker;
};



#endif
